package com.hz.tgb.data.mongo;

import com.mongodb.MongoClientOptions;
import com.mongodb.MongoClientSettings;
import com.mongodb.MongoCredential;
import com.mongodb.ServerAddress;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.connection.ConnectionPoolSettings;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;


/**
 * Mongo配置
 *
 * @author hezhao created on 2019/12/5 8:59
 */
@Configuration
@Slf4j
//@EnableMongoRepositories(basePackages = "com.hz.tgb.data.mongo.repository")
public class MongoConfig {

    @Value("${spring.data.mongodb.uri}")
    private String uri;
    @Value("${spring.data.mongodb.database}")
    public String database;
    @Value("${spring.data.mongodb.user}")
    public String user;
    @Value("${spring.data.mongodb.password}")
    public String password;
    /** 允许的最大连接数 */
    @Value("${spring.data.mongodb.minPoolSize:10}")
    public Integer minPoolSize;
    /** 允许的最小连接数 */
    @Value("${spring.data.mongodb.maxPoolSize:200}")
    public Integer maxPoolSize;
    /** 这是池中连接可用的最大等待队列数 */
    @Value("${spring.data.mongodb.maxWaitQueueSize:2000}")
    public Integer maxWaitQueueSize;
    /** 连接的最大空闲时间 */
    @Value("${spring.data.mongodb.maxConnectionIdleTime:8}")
    public Long maxConnectionIdleTime;
    /** 连接可以生存的最长时间 */
    @Value("${spring.data.mongodb.maxConnectionLifeTime:720}")
    public Long maxConnectionLifeTime;
    /** 线程等待连接可用的最长时间 */
    @Value("${spring.data.mongodb.maxWaitTime:8}")
    public Long maxWaitTime;

    @Bean(name = "mongoTemplate")
    public MongoTemplate mongoTemplate(@Autowired MongoDbFactory mongoDbFactory) {
        return new MongoTemplate(mongoDbFactory);
    }

    @Bean(name = "mongoDbFactory")
    public MongoDbFactory mongoDbFactory(@Autowired com.mongodb.MongoClient oldMongoClient) {
        return new SimpleMongoDbFactory(oldMongoClient, database);
    }

    // 老client
    @Bean(name = "oldMongoClient")
    public com.mongodb.MongoClient oldMongoClient() {
        List<ServerAddress> serverAddressList = getServerAddressList();
        MongoClientOptions mongoClientOptions = MongoClientOptions.builder().connectionsPerHost(maxPoolSize).minConnectionsPerHost(minPoolSize)
                .threadsAllowedToBlockForConnectionMultiplier(maxWaitQueueSize / maxPoolSize)
                .maxWaitTime((int) TimeUnit.SECONDS.toMillis(maxWaitTime))
                .maxConnectionIdleTime((int) TimeUnit.SECONDS.toMillis(maxConnectionIdleTime))
                .maxConnectionLifeTime((int) TimeUnit.SECONDS.toMillis(maxConnectionLifeTime)).build();
        MongoCredential credential = MongoCredential.createCredential(user, database, password.toCharArray());
        com.mongodb.MongoClient mongoClient = new com.mongodb.MongoClient(serverAddressList, credential, mongoClientOptions);
        return mongoClient;
    }

    // 新client
    @Bean(name = "mongoClient")
    public MongoClient getMongoClient() {
        ConnectionPoolSettings connectionPoolSettings = ConnectionPoolSettings
                .builder().maxSize(maxPoolSize).minSize(minPoolSize)
                .maxWaitQueueSize(maxWaitQueueSize)
                .maxWaitTime(maxWaitTime, TimeUnit.SECONDS)
                .maxConnectionIdleTime(maxConnectionIdleTime,TimeUnit.SECONDS)
                .maxConnectionLifeTime(maxConnectionLifeTime,TimeUnit.SECONDS).build();
        List<ServerAddress> serverAddressList = getServerAddressList();
        MongoCredential credential = MongoCredential.createCredential(user, database, password.toCharArray());
        MongoClientSettings settings = MongoClientSettings.builder()
                .credential(credential)
                .applyToConnectionPoolSettings(builder -> builder.applySettings(connectionPoolSettings))
                .applyToSslSettings(builder -> builder.enabled(false))
                .applyToClusterSettings(builder ->
                        builder.hosts(serverAddressList))
                .build();
        MongoClient mongoClient = MongoClients.create(settings);
        return mongoClient;
    }

    // 获取集群配置
    private List<ServerAddress> getServerAddressList() {
        String[] hostList = uri.split(",");
        List<ServerAddress> serverAddressList = new ArrayList<>();
        for (String hs : hostList) {
            String ip = hs.substring(0, hs.indexOf(":"));
            int port = Integer.parseInt(hs.substring(hs.indexOf(":") + 1));
            serverAddressList.add(new ServerAddress(ip, port));
        }
        return serverAddressList;
    }

}
